package com.bestflashsolutions.components
{
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.NetStatusEvent;
	import flash.events.TimerEvent;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	import mx.controls.Alert;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	
	
	public class StreamVideoPlayer extends UIComponent
	{
		protected const BUFFER_TIME:Number = 8;
		public var defaultVolume:Number = .50;
		public var lastVolume:Number = defaultVolume;
		public var muted:Boolean = false;
		public var smoothing:Boolean = true;
		public var loop:Boolean = false;
		public var playerWidth:Number = 200;
		public var playerHeight:Number = 150;
		protected var newSource:String = "";
		protected var oldSource:String = "";
		protected var videoPlayer:Video;
		protected var netConnection:NetConnection;
		protected var netStream:NetStream;
		protected var vidInfo:Object;
		
		private var _autoplay:Boolean = false;
		
		private var _oldConnectionString:String;
		
		public function set autoplays(value:Boolean):void{
			_autoplay = value;
		}
		
		public function StreamVideoPlayer()
		{
			super();
			this.addEventListener(FlexEvent.CREATION_COMPLETE, init);
			createUnderlyingVideoPlayer();
			var tempArray:Array = new Array();
			tempArray["duration"] = 0;
			vidInfo = tempArray;
		}
		
		private function init(event:FlexEvent):void
		{
			this.removeEventListener(FlexEvent.CREATION_COMPLETE, init);
			videoPlayer.visible = true;
			trace(this.width, this.height, videoPlayer.height, videoPlayer.width);
		}
		
		public function play():void
		{
			if(newSource == oldSource)
			{
				dispatchNeedToSeek();
			} else {
				if(netStream)
					netStream.play(newSource);
			}
		}
		
		public function pause():void
		{
			netStream.pause();
		}
		
		public function resume():void
		{
			netStream.resume();
		}
		
		public function stop():void
		{
			if(netStream){
				netStream.pause();
				netStream.close();
			}
		}
		
		public function seek(timeToSeekTo:Number):void
		{
			netStream.seek(timeToSeekTo);
		}
		
		public function mute():void
		{
			if(!muted)
			{
				lastVolume = netStream.soundTransform.volume;
				setVolume(0);
				muted = true;
			} else {
				setVolume(lastVolume);
				muted = false;
			}
		}
		
		public function get currentTime():Number
		{
			return netStream.time;
		}
		
		public function get duration():Number
		{
			return vidInfo.duration;
		}
		
		public function get source():String
		{
			return newSource;
		}
		
		public function set source(sourceToSet:String):void
		{
			oldSource = newSource;
			newSource = sourceToSet;
		}
		
		public function set volume(volumeToSet:Number):void
		{
			if(muted)
			{
				mute();
			} else {
				setVolume(volumeToSet);     
			}
		}
		
		public function onMetaData(info:Object):void
		{
			var oldVidInfo:Number = vidInfo.duration;
			vidInfo = info;
			if(oldVidInfo != vidInfo.duration)
			{
				dispatchDurationChange();
			}
			resizeVideo();
		}
		
		public function onXMPData(info:Object):void
		{
			var oldVidInfo:Number = vidInfo.duration;
			vidInfo = info;
			if(oldVidInfo != vidInfo.duration)
			{
				dispatchDurationChange();
			}
			resizeVideo();
		}
		
		protected function createUnderlyingVideoPlayer():void
		{
			// create our Video object, attach it to the stage, and resize it (critical--since otherwise, both height and width would be 0).
			videoPlayer = new Video();
			this.addChild(videoPlayer);
			videoPlayer.width = playerWidth;
			videoPlayer.height = playerHeight;
			videoPlayer.x = 0;
			videoPlayer.y = 0;
			
			
		}
		
		public function changeRoom(connectionString:String, roomGuid:String){
			if(roomGuid != _oldConnectionString){
				_oldConnectionString = roomGuid;
				netConnection = new NetConnection();
				netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
				netConnection.connect(connectionString+"/"+roomGuid);
				
				/**/
			}
		}
		
		protected function resizeVideo():void
		{
			videoPlayer.width = playerWidth;
			videoPlayer.height = ((playerWidth * vidInfo.height) / vidInfo.width);
			videoPlayer.x = 0;
			videoPlayer.y = ((playerHeight - videoPlayer.height) / 2);
		}
		
		protected function setVolume(volumeToSet:Number):void
		{
			var soundTransform:SoundTransform = new SoundTransform(volumeToSet);
			netStream.soundTransform = soundTransform;
		}
		
		protected function loopVideo():void
		{
			netStream.seek(0);
		}
		
		private function ns_onCuePoint(item:Object):void {
			trace("cue");
		}
		
		protected function netStatusHandler(event:NetStatusEvent):void
		{
			switch (event.info.code)
			{
				case "NetStream.Play.StreamNotFound":
					trace("Error. Stream not found: " + source);
					Alert.show("File Not Found");
					break;
				case "NetConnection.Connect.Success":
					if(netStream == null){
						var nsClient:Object = {};
						nsClient.onMetaData = onMetaData;
						nsClient.onXMPData = onXMPData;
						nsClient.onCuePoint = ns_onCuePoint;
						
						netStream = new NetStream(netConnection);
						netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
						netStream.client = nsClient;
						netStream.bufferTime = BUFFER_TIME;
						
						setVolume(defaultVolume);
						videoPlayer.attachNetStream(netStream);
						
						if(_autoplay)
							play();
					}
					break;
				case "NetStream.Play.Stop":
					if(loop)
					{
						loopVideo();
					} else {
						var playedTime:Number = int(netStream.time);
						var totalTime:Number = int(vidInfo.duration);
						// if we're within 2 seconds of the end, assume we're at the end.
						if(Math.abs(totalTime - playedTime) <= 1)
						{
							dispatchComplete();
						}
					}
					break;
			}
		}
		
		protected function dispatchComplete():void
		{
			var eventObj:TimerEvent = new TimerEvent("complete");
			dispatchEvent(eventObj);
		}
		
		protected function dispatchDurationChange():void
		{
			var eventObj:TimerEvent = new TimerEvent("durationChange");
			dispatchEvent(eventObj);
		}
		
		protected function dispatchNeedToSeek():void
		{
			var eventObj:Event = new Event("needToSeek");
			dispatchEvent(eventObj);
		}
		
	}
}